package com.yjq.blog.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonResponse;
import com.yjq.blog.enums.ErrorCodeEnum;
import com.yjq.blog.service.SendMessageService;
import com.yjq.blog.user.config.AliMessageConfig;
import com.yjq.blog.user.constant.CodeConstant;
import com.yjq.blog.user.entity.User;
import com.yjq.blog.user.repository.UserRepository;
import com.yjq.blog.user.service.LoginService;
import com.yjq.blog.user.vo.UserLoginVO;
import com.yjq.blog.user.vo.UserRegistryVO;
import com.yjq.blog.utils.HttpServletUtil;
import com.yjq.blog.vo.AliMessage;
import com.yjq.blog.vo.Response;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class LoginServiceImpl implements LoginService {

    @Resource
    private SendMessageService sendMessageService;

    @Resource
    private UserRepository userRepository;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private AliMessageConfig message;

    @Value("${aliyun.message.templateCode.captcha}")
    private String templateCode;

    @Override
    public Response<UserLoginVO> login(String phone, Integer code) {
        String codeKey = CodeConstant.getCodeKey(phone, "login");
        Integer redisCode = (Integer)redisTemplate.opsForValue().get(codeKey);

        if(code.equals(redisCode)) {
            User user = userRepository.findFirstByPhone(phone);
            user.setLastLoginTime(new Date());
            UserLoginVO loginVO = new UserLoginVO();
            BeanUtils.copyProperties(user, loginVO);
            try {
                redisTemplate.delete(codeKey);
            } catch (Exception e) {
                log.error("删除登录验证码失败：key：" + codeKey);
            }
            try {
                userRepository.save(user);
            } catch (Exception e) {
                log.error("更新用户登录时间失败：" + user);
            }
            return Response.success(loginVO);
        } else {
            return Response.fail(ErrorCodeEnum.CODE_ERROR);
        }
    }

    @Override
    public Response<UserLoginVO> passwordLogin(String phone, String password) {
        User user = userRepository.findFirstByPhone(phone);
        if(user == null) {
            return Response.fail(ErrorCodeEnum.USER_NOT_EXIST);
        }
        if(!password.equals(user.getPassword())) {
          return Response.fail(ErrorCodeEnum.PASSWORD_IS_ERROR);
        }
        UserLoginVO loginVO = new UserLoginVO();
        BeanUtils.copyProperties(user, loginVO);
        return Response.success(loginVO);
    }

    @Override
    public Response getCode(String phone, String type, HttpServletRequest request) {

        String ip = HttpServletUtil.getRemoteIP(request);
        String codeKey = CodeConstant.getCodeKey(phone, type);
        String ipTotalTimesKey = CodeConstant.getIpTotalTimesKey(ip);
        String phoneTotalTimesKey = CodeConstant.getPhoneTotalTimesKey(phone);

        // 同一手机号, 1分钟内不能发送两次
        Boolean hasKey = redisTemplate.hasKey(codeKey);
        if(hasKey != null && hasKey) {
            return Response.fail(ErrorCodeEnum.PHONE_TIME_LIMIT);
        }
        // 同一手机号, 每天累计不能超过20次
        redisTemplate.opsForValue().get(phoneTotalTimesKey);
        Object phoneTimes = redisTemplate.opsForValue().get(phoneTotalTimesKey);
        if(phoneTimes != null && (Integer)phoneTimes >= 20) {
            return Response.fail(ErrorCodeEnum.PhONE_TIMES_LIMIT);
        }
        // 同一ip地址, 每天累计不能超过20次
        Object ipTimes = redisTemplate.opsForValue().get(ipTotalTimesKey);
        if(ipTimes != null && (Integer)ipTimes >= 20) {
            return Response.fail(ErrorCodeEnum.IP_TIMES_LIMIT);
        }

        if(!"registry".equals(type)) {
            User user = userRepository.findFirstByPhone(phone);
            if (user == null) {
                return Response.fail(ErrorCodeEnum.PHONE_NOT_EXIST);
            }
        }

        Integer code = RandomUtils.nextInt(100000, 999999);
        CommonResponse response = sendMessageService.sendMessage(phone, Map.of("code", code), "蜡笔小钦", templateCode, message.getAliMessage());
        log.info(JSONObject.toJSONString(response));

        if(response != null) {
            JSONObject object = JSONObject.parseObject(response.getData());
            Object responseCode = object.get("Code");
            if(response.getHttpStatus() == 200 && "OK".equals(responseCode)) {
                // 调用api成功
                redisTemplate.opsForValue().set(codeKey, code, 300, TimeUnit.SECONDS);
                redisTemplate.opsForValue().set(phoneTotalTimesKey, phoneTimes == null ? 1 : (Integer)phoneTimes + 1, 1, TimeUnit.DAYS);
                redisTemplate.opsForValue().set(ipTotalTimesKey, ipTimes == null ? 1 : (Integer)ipTimes + 1, 1, TimeUnit.DAYS);
                return Response.success("发送成功");
            }
            return Response.fail(ErrorCodeEnum.SEND_FAIL, response.getData());
        } else {
            return Response.fail(ErrorCodeEnum.SEND_FAIL);
        }
    }

    @Override
    public Response<UserLoginVO> registry(UserRegistryVO userRegistryVO) {

        String codeKey = CodeConstant.getCodeKey(userRegistryVO.getPhone(), "registry");
        Integer redisCode = (Integer)redisTemplate.opsForValue().get(codeKey);

        if(userRegistryVO.getCode() == null) {
            return Response.fail(ErrorCodeEnum.REGISTRY_CODE_IS_NULL);
        } else if (!userRegistryVO.getCode().equals(redisCode)){
            return Response.fail(ErrorCodeEnum.REGISTRY_CODE_ERROR);
        }
        User user = userRepository.findFirstByPhone(userRegistryVO.getPhone());
        if (user != null) {
            return Response.fail(ErrorCodeEnum.REGISTRY_PHONE_IS_EXIST);
        }

        User saveUser = new User();
        BeanUtils.copyProperties(userRegistryVO, saveUser);
        saveUser.setCreateTime(new Date());
        saveUser = userRepository.save(saveUser);

        UserLoginVO loginVO = new UserLoginVO();
        BeanUtils.copyProperties(saveUser, loginVO);
        return Response.success(loginVO);
    }

}
